#!/bin/bash -e
#
#   Neutron3529's Unity Game Plugin
#   Copyright (C) 2022 Neutron3529
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
############################################################################
#
#   * compile instructions: put this file and `utils.cs` in `steamapps`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x ${file}.cs
#   *     ./${file}.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

export GAME_NAME="${0%\.cs}"                                # might modify if the name mismatch.
export GAME_DIR="Banner of the Maid"                                # might be modified, but "$GAME_NAME" cover most of the cases.

export FILE_NAME="$0"
export ASSEMBLY="Assembly-CSharp"                           # might be modified
export UTILS="utils.cs"                                     # might be modified if you do not put utils.cs in the current dir.
export PLUGIN_ID="Neutron3529.Cheat"                        # should be modified
export NAMESPACE_ID="Neutron3529.Cheat"                     # should be modified
export GAME_BASE_DIR="common/$GAME_DIR"                     # should modify GAME_DIR instead since GAME_DIR == GAME_NAME is almost always true.

export IFS=$'\n' # to disable the annoying space.
export DOTNET="dotnet" # the location of the DOTNET executable file.
[ -z "$DOTNET_CSC_DLL" ] && export DOTNET_CSC_DLL=`\ls /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll` # In manjaro, the csc.dll is located in /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll

case $1 in
  V)       EXTRA_DEFINE="-define:DEBUG${IFS}-define:VERBOSE${IFS}-debug" ;;
  v)       EXTRA_DEFINE="-define:DEBUG${IFS}-define:VERBOSE${IFS}-debug" ;;
  VERBOSE) EXTRA_DEFINE="-define:DEBUG${IFS}-define:VERBOSE${IFS}-debug" ;;
  verbose) EXTRA_DEFINE="-define:DEBUG${IFS}-define:VERBOSE${IFS}-debug" ;;
  D)       EXTRA_DEFINE="-define:DEBUG${IFS}-debug"                      ;;
  d)       EXTRA_DEFINE="-define:DEBUG${IFS}-debug"                      ;;
  DEBUG)   EXTRA_DEFINE="-define:DEBUG${IFS}-debug"                      ;;
  debug)   EXTRA_DEFINE="-define:DEBUG${IFS}-debug"                      ;;
  *)       EXTRA_DEFINE=""                                               ;;
esac

_MODE__SELECT_=100

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $DOTNET $DOTNET_CSC_DLL -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Harmony.dll" \
  `[ -e "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.UI.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/mscorlib.dll" \
  $(for i in "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/$ASSEMBLY"*.dll ; do echo -e "-r:\"$i\"\n" ; done) \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize $EXTRA_DEFINE \
  - $UTILS && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
  git add ${FILE_NAME}
  case $2 in
    R) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    r) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    RANDOM) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    random) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    U) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    u) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    UPLOAD) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    upload) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
    *) git commit -am "$2" ;;
  esac
  git push
fi
exit








using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

namespace %%NAMESPACE_ID%%;

[BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.0")]
public class Cheat : Neutron3529.ModEntry {
    public Cheat() : base("%%PLUGIN_ID%%") {}
    public override void Awake() {
        base.Awake();
        // 主要逻辑放在`utils.cs`中，这里的Awake2只是为了以防万一
        // 目前来说，这个函数的唯一用途是用来“叮”……
        // 就像这样：
        logger("叮~修改器启动，请安心游戏");
    }
    [Desc("购买技能不减钱")]
    class fix_talent : Entry {
        [HarmonyPatch(typeof(France.Game.model.role.Role),"buySkill")]
        public static IEnumerable<CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable<CodeInstruction> instructions) {
            logger("%%PLUGIN_ID%%-正在注入类别"+__originalMethod.DeclaringType.Name+"的"+__originalMethod.Name+"方法");
            instructions = new CodeMatcher(instructions)
                .MatchForward(false, // false = move at the start of the match, true = move at the end of the match
                    new CodeMatch(OpCodes.Stsfld,typeof(France.Game.model.PlayerData).GetField("Money"))
                ).Repeat( matcher => // Do the following for each match
                    matcher
                        .SetAndAdvance(
                            OpCodes.Pop,null
                        )
                        .Advance(1),
                    logger
                ).InstructionEnumeration();
            return instructions;
        }
    }
    class lvup_many_times : Entry {
        [Desc("额外升级次数","gt",0)]
        static int extra_up=0;
        [HarmonyPatch(typeof(France.Game.model.role.Role),"lvUp")]
        public static void Prefix(France.Game.model.role.Role __instance) {
            for(var i=0;i<extra_up;i++){
                Origin(__instance);
                __instance.lv--;
                __instance.exp+=100;
            }
        }
        [HarmonyReversePatch, HarmonyPatch(typeof(France.Game.model.role.Role),"lvUp")]
        public static void Origin(France.Game.model.role.Role instance) {
            throw new NotImplementedException("It's a stub");
        }
    }
    [Desc("获取经验时学会所有技能")]
    class learn_all_skill : Entry {
        [HarmonyPatch(typeof(France.Game.model.role.Role),"gainExp")]
        public static void Prefix(France.Game.model.role.Role __instance) {
            foreach(var i in __instance.getUnlearnedSkills()){
                __instance.learnNewSkill(new France.Resource.Skill(i),false,false);
            }
        }
    }
    class speed_mul : Entry {
        [Desc("速度倍率","gt",1)]
        static float mul=5f;
        [HarmonyPatch(typeof(France.Game.model.level.GFightUnit),"calcSpd")]
        public static void Postfix(France.Game.model.level.GFightUnit __instance, ref float __result) {
            if(__instance.getTeamId() == 0){
                __result*=mul;
            }
        }
    }
    class dex_mul : Entry {
        [Desc("灵巧倍率","gt",1)]
        static float mul=5f;
        [HarmonyPatch(typeof(France.Game.model.level.GFightUnit),"calcDex")]
        public static void Postfix(France.Game.model.level.GFightUnit __instance, ref float __result) {
            if(__instance.getTeamId() == 0){
                __result*=mul;
            }
        }
    }
    [Desc("士气在攻击后充满")]
    class mp_set : Entry {
        [HarmonyPatch(typeof(France.Game.model.level.GFightUnit),"calcMpGain")]
        public static void Postfix(France.Game.model.level.GFightUnit __instance, ref float __result) {
            if(__instance.getTeamId() == 0){
                __result=100f;
            }
        }
    }
    [Desc("玩家无限再动")]
    class set_done : Entry {
        [HarmonyPatch(typeof(France.Game.model.level.GFightUnit),"setDone")]
        public static void Prefix(France.Game.model.level.GFightUnit __instance, ref bool done) {
            if(__instance.getTeamId() == 0){
                done=false;
            }
        }
    }
    [Desc("玩家无视地形损耗")]
    class GFightUnitgetBuffMoveCost : Entry {
        [HarmonyPatch(typeof(France.Game.model.level.GFightUnit),"getBuffMoveCost")]
        public static void Prefix(France.Game.model.level.GFightUnit __instance, ref float __result) {
            if(__instance.getTeamId() == 0){
                __result=-10000f;
            }
        }
    }

}
